{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "# Python 系统管理\n",
    "\n",
    "## 操作系统\n",
    "\n",
    "Python的`os`模块实现了与操作系统相关的功能的接口。\n",
    "这些操作包括遍历目录树，删除/重命名文件等。\n",
    "其中`os.path`模块可以实现一些针对路径名的操作。\n",
    "\n",
    "### `os`模块\n",
    "\n",
    "#### 文件处理\n",
    "\n",
    "* `remove()` / `unlink()`    删除文件\n",
    "* `rename()` / `renames()`   重命名文件\n",
    "* `stat()`               返回文件信息\n",
    "* `symlink()`            创建符号链接\n",
    "* `utime()`              更新时间戳\n",
    "* `walk(top, topdown=True, onerror=None, followlinks=False)`\n",
    "\n",
    "   **生成一个目录树下的所有文件名**，方式是按**上->下**或**下->上**顺序浏览目录树。\n",
    "   对于以`top`为根的目录树中的每个目录（包括`top`本身），\n",
    "   它都会生成一个三元组`(dirpath, dirnames, filenames)`。\n",
    "   \n",
    "   * `dirpath` 是一个字符串，表示目录的路径。\n",
    "   * `dirnames` 是一个列表，内含`dirpath`中子目录的名称（不包括 `'.'` 和 `'..'` ）。\n",
    "   * `filenames` 也是列表，内含 `dirpath` 中文件（非目录）的名称。\n",
    "\n",
    "#### 目录/文件夹\n",
    "\n",
    "* `mkdir()` / `mkdirs()`     创建目录/创建多层目录\n",
    "* `rmdir()` / `removedirs()` 删除目录/删除多层目录\n",
    "* `listdir()`            **列出指定目录的文件**\n",
    "* `chdir()` / `fcdir()`      改变当前工作目录 / 通过一个文件描述符改变当前目录\n",
    "* `chroot()`             改变当前进程的根目录\n",
    "* `getcwd()` / `getcwdu()`   返回当前工作目录 / 功能相同，但返回Unicode对象\n",
    "\n",
    "#### 访问/权限\n",
    "\n",
    "* `access()`             检验权限模式\n",
    "* `chmod()`              改变权限模式\n",
    "* `chown()` / `lchown()`     改变owner和group ID / 功能相同，但不会跟踪链接\n",
    "* `umask()`              设置默认权限模式\n",
    "\n",
    "### `os.path`常用路径操作\n",
    "\n",
    "#### 分隔\n",
    "\n",
    "-   <code>basename()</code>去掉目录路径，返回文件名\n",
    "-   <code>dirname()</code>去掉文件名，返回目录路径\n",
    "-   <code>join()</code>将分隔的部分组合成路径\n",
    "-   <code>split()</code>返回<code>(dirname(), basename())</code>元组\n",
    "-   <code>splitdrive()</code>返回<code>(drivename, pathname)</code>元组在没有驱动器概念的系统上，<code>drive</code>将始终为空字符串。在所有情况下，=drivename + pathname= 都与<code>path</code>相同。\n",
    "-   <code>splitext()</code>返回<code>(filename, extension)</code>元组\n",
    "-   <code>commonpath(paths)</code>接受包含多个路径的序列<code>paths</code>，返回<code>paths</code>的最长公共子路径。\n",
    "-   <code>commonprefix(list)</code>接受包含多个路径的列表，返回所有路径的最长公共前缀（逐字符比较）。如果列表为空，则返回空字符串。\n",
    "\n",
    "#### 信息\n",
    "\n",
    "-   <code>getatime()</code>返回最近访问时间\n",
    "-   <code>getctime()</code>返回文件创建时间\n",
    "-   <code>getmtime()</code>返回最近文件修改时间\n",
    "-   <code>getsize()</code>返回文件大小\n",
    "\n",
    "#### 查询\n",
    "\n",
    "-   <code>exists()</code>指定路径（文件或者目录）是否存在\n",
    "-   <code>lexists()</code>如果<code>path</code>指向一个已存在的路径，返回<code>True</code>。对于失效的符号链接，也返回<code>True</code>。\n",
    "-   <code>isabs()</code>指定路径是否为绝对路径\n",
    "-   <code>isdir()</code>指定路径是否存在且是一个目录\n",
    "-   <code>isfile()</code>指定路径是否存在且是一个文件\n",
    "-   <code>islink()</code>指定路径是否存在且是一个符号链接\n",
    "-   <code>ismount()</code>指定路径是否存在且是一个挂载点\n",
    "-   <code>samefile()</code>两个路径名是否指向同一个文件\n",
    "\n",
    "#### 其他\n",
    "\n",
    "-   <code>normpath</code>\n",
    "    \n",
    "    用来规范化路径。\n",
    "    \n",
    "    通过折叠多余的分隔符和对上级目录的引用来标准化路径名。\n",
    "\n",
    "-   <code>abspath(path)</code>\n",
    "    \n",
    "    返回路径<code>path</code>的绝对路径（标准化的）。\n",
    "\n",
    "-   <code>realpath(path)</code>\n",
    "    \n",
    "    返回指定文件的规范路径，消除路径中存在的任何符号链接（如果操作系统支持）。\n",
    "\n",
    "-   <code>expanduser(path)</code>\n",
    "    \n",
    "    在 Unix 和 Windows 上，将参数中开头部分的<code>~</code>或<code>~user</code>替换为当前<code>用户</code>的家目录并返回。\n",
    "\n",
    "-   <code>expandvars(path)</code>\n",
    "    \n",
    "    输入带有环境变量的路径作为参数，返回展开变量以后的路径。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-05-13T08:10:21.139115Z",
     "start_time": "2020-05-13T08:10:21.132134Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".\n",
      "['.ipynb_checkpoints', 'PaC']\n",
      "['1-4review.ipynb', '10_mangle_data.ipynb', '11_regular_expressions.ipynb', '12_file_io_and_structured_text_files.ipynb', '13_system_management.ipynb', '3 string.ipynb', '4. Python基本数据结构(全).ipynb', '5review.ipynb', '6_exceptions.ipynb', '7_模块和包.ipynb', 'Class0311-checkpoint.ipynb', 'Class0311.ipynb', 'class0318.ipynb', 'class0318.py', 'Class0325.ipynb', 'Class0401对象和类.ipynb', 'class0408.ipynb', 'Class0415.ipynb', 'Class0422.ipynb', 'class0429.ipynb', 'Class0506.ipynb', 'data.json', 'test1_2_19.ipynb', 'Untitled.ipynb']\n",
      "\n",
      ".\\.ipynb_checkpoints\n",
      "[]\n",
      "['13_system_management-checkpoint.ipynb', '3 string-checkpoint.ipynb', 'class0318-checkpoint.ipynb', 'Class0325-checkpoint.ipynb', 'Class0401对象和类-checkpoint.ipynb', 'class0408-checkpoint.ipynb', 'Class0422-checkpoint.ipynb', 'class0429-checkpoint.ipynb', 'Class0506-checkpoint.ipynb', 'test1_2_19-checkpoint.ipynb', 'Untitled-checkpoint.ipynb']\n",
      "\n",
      ".\\PaC\n",
      "['.ipynb_checkpoints']\n",
      "['class325.py', 'RequestsBook.ipynb']\n",
      "\n",
      ".\\PaC\\.ipynb_checkpoints\n",
      "[]\n",
      "['RequestsBook-checkpoint.ipynb']\n",
      "\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "for dirname,dirpaths,filepaths in os.walk('.'):\n",
    "    print(dirname)\n",
    "    print(dirpaths)\n",
    "    print(filepaths)\n",
    "    print()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `fnmatch` Unix 文件名模式匹配\n",
    "此模块提供了 Unix shell 风格的通配符，它们 **不** 等同于正则表达式（参见 `re` 模块）。\n",
    "\n",
    "shell 风格通配符所使用的特殊字符如下：\n",
    "\n",
    "| 模式     | 意义                        |\n",
    "|----------|-----------------------------|\n",
    "| `*`      | 匹配所有                    |\n",
    "| `?`      | 匹配任何单个字符            |\n",
    "| `[seq]`  | 匹配 `seq` 中的任何字符     |\n",
    "| `[!seq]` | 匹配任何不在 `seq` 中的字符 |\n",
    "\n",
    "对于字面值匹配，需将原字符用方括号括起来。 例如，<code>'[?]'</code>将匹配字符<code>'?'</code>。\n",
    "\n",
    "-   <code>fnmatch.fnmatch(filename, pattern)</code>\n",
    "\n",
    "    检测<code>filename</code>字符串是否匹配<code>pattern</code>字符串，返回<code>True</code>或<code>False</code>。两个形参都会使用<code>os.path.normcase()</code>进行大小写正规化。<code>fnmatch.fnmatchcase()</code>可被用于执行大小写敏感的比较，无论这是否为所在操作系统的标准。\n",
    "\n",
    "    示例：获取当前目录下带有特定扩展名的所有文件。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def find_files_in_dir(dir, pattern):\n",
    "    import fnmatch\n",
    "    import os\n",
    "    return (file for file in os.listdir(dir)\n",
    "            if fnmatch.fnmatch(file, pattern))\n",
    "\n",
    "for file in find_files_in_dir('.', '*.org'):\n",
    "    print(file)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-05-20T06:40:45.340153Z",
     "start_time": "2020-05-20T06:40:45.327919Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "F:\\2020_University_two\\newNoteBooks\\course_and_study_new\\python计算生态\\JupyterNotebooks\\Class0219.md\n",
      "F:\\2020_University_two\\newNoteBooks\\course_and_study_new\\python计算生态\\JupyterNotebooks\\class0304.md\n"
     ]
    }
   ],
   "source": [
    "def find_files_in_dir(dir, pattern):\n",
    "    import fnmatch\n",
    "    import os\n",
    "    return (os.path.realpath(file) for file in os.listdir(dir)\n",
    "            if fnmatch.fnmatch(file, pattern))\n",
    "\n",
    "path='F:\\\\2020_University_two\\\\newNoteBooks\\\\course_and_study_new\\\\python计算生态\\\\Notebooks\\\\'\n",
    "for file in find_files_in_dir(path,'*.md'):\n",
    "    print(file)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "-   <code>fnmatch.filter(names, pattern)</code>\n",
    "\n",
    "    返回<code>names</code>列表中匹配<code>pattern</code>的子集。\n",
    "    它等价于<code>[n for n in names if fnmatch(n, pattern)]</code>，但其实现更为高效。\n",
    "-   <code>fnmatch.translate(pattern)</code>\n",
    "\n",
    "    返回 shell 风格<code>pattern</code>转换成的正则表达式以便用于<code>re.match()</code>。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-05-20T06:49:34.694124Z",
     "start_time": "2020-05-20T06:49:34.680521Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(?s:.*\\.txt)\\Z\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<re.Match object; span=(0, 10), match='foobar.txt'>"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import fnmatch, re\n",
    "\n",
    "regex = fnmatch.translate('*.txt')  # => '(?s:.*\\\\.txt)\\\\Z'\n",
    "print(regex)\n",
    "reobj = re.compile(regex)\n",
    "reobj.match('foobar.txt')  # => <re.Match object; span=(0, 10), match='foobar.txt'>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "### `glob` Unix 风格路径名模式扩展\n",
    "\n",
    "使用Unix shell的规则来匹配文件或者目录。\n",
    "\n",
    "- `glob.glob(pathname, *, recursive=False)`\n",
    "\n",
    "  返回匹配 `pathname` 的可能为空的路径名列表，其中的元素必须为包含一个路径信息的字符串。\n",
    "\n",
    "考虑一个包含以下内容的目录：文件 `1.gif` , `2.txt` , `card.gif` 以及\n",
    "一个子目录 `sub` 其中只包含一个文件 `3.txt` 。请注意路径的任何开头部分都将被保留："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "import glob\n",
    "glob.glob('./[0-9].*')   # ['./1.gif', './2.txt']\n",
    "glob.glob('*.gif')  # ['1.gif', 'card.gif']\n",
    "glob.glob('?.gif')  # ['1.gif']\n",
    "glob.glob('**/*.txt', recursive=True)  # ['2.txt', 'sub/3.txt']\n",
    "glob.glob('./**/', recursive=True)  # ['./', './sub/']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果目录包含以 `.` 打头的文件，它们默认将不会被匹配。\n",
    "例如，考虑一个包含 `card.gif` 和 `.card.gif` 的目录："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import glob\n",
    "glob.glob('*.gif')  # ['card.gif']\n",
    "glob.glob('.c*')  # ['.card.gif']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 实现一个函数，搜索一个指定目录下文件名符合特定模式（Unix shell）的文件并返回文件的绝对路径，支持选择递归搜索。返回一个列表    walk   fmatch    f"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-05-21T08:11:58.025467Z",
     "start_time": "2020-05-21T08:11:58.013749Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['F:\\\\2020_University_two\\\\newNoteBooks\\\\course_and_study_new\\\\python计算生态\\\\XLwork']"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import glob\n",
    "path='F:\\\\2020_University_two\\\\newNoteBooks\\\\course_and_study_new\\\\python计算生态\\\\XLwork'\n",
    "pattern='*.py'\n",
    "glob.glob(pathname=path)  # ['card.gif']\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-05-21T08:10:19.119184Z",
     "start_time": "2020-05-21T08:10:19.043617Z"
    }
   },
   "outputs": [],
   "source": [
    "?glob.glob"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-05-21T08:12:31.601991Z",
     "start_time": "2020-05-21T08:12:31.589763Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['class0318.py', 'PaC\\\\class325.py']"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import glob\n",
    "path='F:\\\\2020_University_two\\\\newNoteBooks\\\\course_and_study_new\\\\python计算生态\\\\XLwork'\n",
    "pattern='*.py'\n",
    "glob.glob('**/*.py', recursive=True) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-05-21T08:13:46.057993Z",
     "start_time": "2020-05-21T08:13:46.045533Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[]"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import glob\n",
    "path='F:\\\\2020_University_two\\\\newNoteBooks\\\\course_and_study_new\\\\python计算生态\\\\XLwork'\n",
    "pattern='*.py'\n",
    "glob.glob('**/**/*.py', recursive=False) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "## 日期和时间\n",
    "\n",
    "### `datetime`模块\n",
    "\n",
    "其定义了4个主要的对象，每个对象处理的内容：\n",
    "\n",
    "* `date` 处理年、月、日\n",
    "* `time` 处理时、分、秒和微秒\n",
    "* `datetime` 处理日期和时间同时出现的情况\n",
    "* `timedelta` 处理日期和（或）时间间隔\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-05-20T07:57:55.524321Z",
     "start_time": "2020-05-20T07:57:55.516373Z"
    },
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "21 4 2017\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'2017-04-21'"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from datetime import date\n",
    "\n",
    "\n",
    "halloween = date(2017, 4, 21)\n",
    "halloween\n",
    "print(halloween.day, halloween.month, halloween.year)\n",
    "halloween.isoformat()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "**iso**是指ISO 8601，一种表示日期和时间的国际标准。这个标准的显示顺序是从一般（年）到特殊（日）。其可用来对日期进行正确的排序：先按照年，然后是月，最后是日。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-05-20T07:57:58.741390Z",
     "start_time": "2020-05-20T07:57:58.737371Z"
    },
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "datetime.date(2020, 5, 20)"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "now = date.today()\n",
    "now"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-05-20T07:58:01.158997Z",
     "start_time": "2020-05-20T07:58:01.154975Z"
    },
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2020-05-21\n",
      "2020-06-06\n",
      "2020-05-19\n",
      "datetime.timedelta(microseconds=1)\n"
     ]
    }
   ],
   "source": [
    "from datetime import timedelta\n",
    "\n",
    "now = date.today()\n",
    "one_day = timedelta(days=1)\n",
    "tomorrow = now + one_day\n",
    "print(tomorrow)\n",
    "print(now + 17 * one_day)\n",
    "yesterday = now - one_day\n",
    "print(yesterday)\n",
    "\n",
    "from datetime import datetime\n",
    "print(repr(datetime.resolution))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "date的范围是`date.min`到`date.max`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "print(date.min)\n",
    "print(date.max)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "`datetime`模块中的`time`对象用来表示一天中的时间："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "from datetime import time\n",
    "\n",
    "noon = time(12, 0, 0)\n",
    "print(noon)\n",
    "print(noon.hour, noon.minute, noon.second, sep=':')\n",
    "print(noon.microsecond)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "参数的顺序按照时间单位从大到小排列（时、分、秒、微秒）。没有参数的话，`time`会默认使用0。\n",
    "\n",
    "注意，时间不一定时精确的，对于**微秒**和**秒**。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "from datetime import datetime\n",
    "\n",
    "def print_repr(obj):\n",
    "    print(repr(obj))\n",
    "\n",
    "some_day = datetime(2017, 4, 21, 2, 43, 50, 7)\n",
    "print_repr(some_day.isoformat())\n",
    "\n",
    "right_now = datetime.now()\n",
    "print_repr(right_now)\n",
    "\n",
    "from datetime import time, date\n",
    "noon = time(12)\n",
    "this_day = date.today()\n",
    "noon_today = datetime.combine(this_day, noon)\n",
    "print_repr(noon_today)\n",
    "\n",
    "print_repr(noon_today.date())\n",
    "print_repr(noon_today.time())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "下面的代码展示计算一个月份的开始日到结束日中间的日期范围："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "from datetime import datetime, date, timedelta\n",
    "import calendar\n",
    "\n",
    "\n",
    "def get_month_range(start_date=None):\n",
    "    if start_date is None:\n",
    "        start_date = date.today().replace(day=1)\n",
    "    _, days_in_month = calendar.monthrange(start_date.year, start_date.month)\n",
    "    end_date = start_date + timedelta(days=days_in_month)\n",
    "    return (start_date, end_date)\n",
    "\n",
    "\n",
    "a_day = timedelta(days=1)\n",
    "first_day, last_day = get_month_range()\n",
    "while first_day < last_day:\n",
    "    print(first_day)\n",
    "    first_day += a_day\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "上面的`get_month_range()`函数接受一个`datetime`对象并返回一个由当前月份开始日和下个月开始日组成的元组对象。\n",
    "\n",
    "计算出一个对应月份第一天的日期，一种快速的方法就是使用`date`或`datetime`对象的`replace()`方法简单地将`days`属性设置成`1`即可。\n",
    "\n",
    "使用`calendar.monthrange()`来获得该月的总天数。任何时候只要你想获得日历信息，可以使用`calendar`模块。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "### `time`模块\n",
    "\n",
    "一种表示绝对时间的方法时计算从某个起始点开始的秒数。Unix时间使用从1970年1月1日0点开始的秒数。这个值通常被成为**纪元**（epoch），它是不同系统之间最简单的交换日期时间的方法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "import time\n",
    "\n",
    "# time() 返回当前时间的纪元值\n",
    "now = time.time()\n",
    "print_repr(now)\n",
    "\n",
    "# ctime() 将纪元值转换成一个字符串\n",
    "print_repr(time.ctime(now))\n",
    "\n",
    "# localtime() 返回当前系统时区下的时间\n",
    "print_repr(time.localtime(now))\n",
    "\n",
    "# gmtime() 返回UTC时间\n",
    "print_repr(time.gmtime(now))\n",
    "\n",
    "print_repr(time.localtime())\n",
    "print_repr(time.gmtime())\n",
    "\n",
    "# mktime() 将 struct_time 对象转换回纪元值\n",
    "print_repr(time.mktime(time.localtime()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "`localtime()`和`gmttime()`返回的是一个`struct_time`对象（命名元组）。其结构如下：\n",
    "\n",
    "| Index | Attribute | Values                                           |\n",
    "|-------|-----------|--------------------------------------------------|\n",
    "|     0 | tm_year   | (for example, 1993)                              |\n",
    "|     1 | tm_mon    | range [1, 12]                                    |\n",
    "|     2 | tm_mday   | range [1, 31]                                    |\n",
    "|     3 | tm_hour   | range [0, 23]                                    |\n",
    "|     4 | tm_min    | range [0, 59]                                    |\n",
    "|     5 | tm_sec    | range [0, 61];                                   |\n",
    "|     6 | tm_wday   | range [0, 6], Monday is 0                        |\n",
    "|     7 | tm_yday   | range [1, 366]                                   |\n",
    "|     8 | tm_isdst  | 0, 1 or -1;                                      |\n",
    "|   N/A | tm_zone   | abbreviation of timezone name                    |\n",
    "|   N/A | tm_gmtoff | offset east of UTC in seconds                    |\n",
    "\n",
    "\n",
    "**建议：**\n",
    "\n",
    "* 尽量多使用UTC来代替时区，特别是将服务器设置为UTC时间，不要使用本地时间。\n",
    "* 有可能的话绝对不使用夏时制时间。\n",
    "\n",
    "\n",
    "### 读写日期和时间\n",
    "\n",
    "使用`strftime()`将日期和时间转换成字符串，`datetime`、`date`、`time`对象和`time`模块中都包含此方法。`strftime()`使用格式化字符串来指定输出，见下表：\n",
    "\n",
    "| 格式化字符串 | 日期/时间单元  |        范围 |\n",
    "|--------------|----------------|-------------|\n",
    "| Y            | 年             |    1900-... |\n",
    "| m            | 月             |       01-12 |\n",
    "| B            | 月名           | January,... |\n",
    "| b            | 月名简写       |     Jan,... |\n",
    "| d            | 日             |       01-31 |\n",
    "| A            | 星期           |  Sunday,... |\n",
    "| a            | 星期缩写       |     Sun,... |\n",
    "| H            | 时（24小时制） |       00-23 |\n",
    "| I            | 时（12小时制） |       01-12 |\n",
    "| p            | 上午/下午      |       AM,PM |\n",
    "| M            | 分             |       00-59 |\n",
    "| S            | 秒             |       00-59 |\n",
    "\n",
    "数字左侧都是补零。更多内容请参考[官方文档](https://docs.python.org/3.6/library/datetime.html#strftime-strptime-behavior)。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "import time\n",
    "\n",
    "fmt = \"It's %A, %B %d, %Y, local time %I:%M:%S%p\"\n",
    "t = time.localtime()\n",
    "print_repr(t)\n",
    "print(time.strftime(fmt, t))\n",
    "\n",
    "\n",
    "from datetime import date\n",
    "\n",
    "some_day = date(2017, 4, 21)\n",
    "print(some_day.strftime(fmt))  # 只能获取日期部分，时间默认是午夜\n",
    "\n",
    "\n",
    "from datetime import time\n",
    "\n",
    "some_time = time(10, 35)\n",
    "print(some_time.strftime(fmt))  # 只会转换时间部分"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "使用`strptime()`可以将格式化的字符串转换为日期或时间。不能使用正则表达式，字符串的非格式化部分必须完全匹配。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "import time\n",
    "\n",
    "fmt = '%Y-%m-%d'\n",
    "print_repr(time.strptime('2017-04-21', fmt))\n",
    "print_repr(time.strptime('2017-04-31', fmt))  # ValueError"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "名称可以通过操作系统中的`locale`进行设置。如果要打印不同的月和日名称，可通过`setlocale()`来设置，其第一个参数是`locale.LC_TIME`，表示设置的是日期和时间，第二个参数是一个结合了**语言**和**国家名称**的缩写字符串。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "import locale\n",
    "help(locale.setlocale)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "import locale\n",
    "from datetime import date\n",
    "\n",
    "halloween = date(2014, 10, 31)\n",
    "for lang_country in ['en_us', 'fr_fr', 'de_de', 'zh_cn']:\n",
    "    locale.setlocale(locale.LC_TIME, lang_country)\n",
    "    print(halloween.strftime('%A, %B %d'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "import locale\n",
    "names = locale.locale_alias.keys()\n",
    "good_names = [name for name in names\n",
    "              if len(name) == 5 and name[2] == '_']\n",
    "for name in list(good_names)[-5:]:\n",
    "    print(name)\n",
    "\n",
    "zh = [name for name in good_names if name.startswith('zh')]\n",
    "print_repr(zh)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "### 其他操作日期和时间的库\n",
    "\n",
    "* [arrow](https://github.com/crsmithdev/arrow)：更好的 Python 日期时间操作类库。\n",
    "* [maya](https://github.com/kennethreitz/maya)：Timestamps for humans.\n",
    "* [dateutil](https://pypi.python.org/pypi/python-dateutil)：Python datetime 模块的扩展。\n",
    "* [delorean](https://github.com/myusuf3/delorean/)：解决 Python 中有关日期处理的棘手问题的库。\n",
    "* [moment](https://github.com/zachwill/moment)：一个用来处理时间和日期的Python库。灵感来自于Moment.js。\n",
    "* [pytz](https://launchpad.net/pytz)：现代以及历史版本的世界时区定义。将时区数据库引入Python。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  },
  "name": "13_system_management.ipynb",
  "toc": {
   "base_numbering": 1,
   "nav_menu": {
    "height": "313.233px",
    "width": "252px"
   },
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": "block",
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
